package com.baidu.foodrecipe.ui.fragment.recipes

import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import androidx.collection.intListOf
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.application
import androidx.lifecycle.viewModelScope
import androidx.room.Query
import com.baidu.foodrecipe.data.local.entity.RecipesEntity
import com.baidu.foodrecipe.data.local.RoomResult
import com.baidu.foodrecipe.data.model.FoodRecipe
import com.baidu.foodrecipe.data.remote.NetworkResult
import com.baidu.foodrecipe.data.repository.Repository
import com.baidu.foodrecipe.utils.ADD_RECIPE_INFORMATION_KEY
import com.baidu.foodrecipe.utils.ADD_RECIPE_INSTRUCTIONS_KEY
import com.baidu.foodrecipe.utils.APIKEY
import com.baidu.foodrecipe.utils.API_KEY
import com.baidu.foodrecipe.utils.CUISINE_KEY
import com.baidu.foodrecipe.utils.DIET_KEY
import com.baidu.foodrecipe.utils.FILL_INGREDIENTS_KEY
import com.baidu.foodrecipe.utils.NUMBER_KEY
import com.baidu.foodrecipe.utils.OFFSET_KEY
import com.baidu.foodrecipe.utils.QUERY_KEY
import com.baidu.foodrecipe.utils.TYPE_KEY
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class MainViewModel(application: Application): AndroidViewModel(application) {
    //记录当前是否有网络
    val isNetworkAvailable = MutableLiveData<Boolean>(true)
    //保存食谱 使用liveData让外部实时监听数据变化
    val foodRecipe = MutableLiveData<FoodRecipe>()
    //是否应该显示加载动画
    val showLoadAnimation = MutableLiveData<Boolean>()
    //网络状态监听回调
    private lateinit var networkCallback: ConnectivityManager.NetworkCallback
    //数据仓库对象
    private val repository = Repository(application)
    private var mealType: String? = null
    private var dietType: String? = null
    private var mQuery: String? = null

    init {
        //当对象被创建时 会调用这个初始化代码库开
        //监听网络状态
        addNetworkListener()
    }

    //给外部提供发起数据请求的方法
    fun getRecipes(){
        isNetworkAvailable.value.also {
            if (it != null && it == true) {
                //有网络 请求网络数据
                safeCall(buildRequestParameters())
            }else{
                //没有网络 请求数据库的数据
                getRecipesFromRoom()
            }
        }
    }

    //加载更多 offset
    fun getMoreRecipes(){
        //获取这次加载的偏移量
        foodRecipe.value?.let {
            safeCall(buildRequestParameters(offset = it.offset + it.number),true)
        }
    }
    //搜索食谱 query mealType dietType
    fun search(mealType: String, dietType: String, query:String? = null){
        this.mealType = mealType
        this.dietType = dietType
        this.mQuery = query
        safeCall(buildRequestParameters(query  = query, mealType = mealType, dietType = dietType))
    }

    private fun safeCall(params: Map<String, String>,isAppend: Boolean = false){
        isNetworkAvailable.value?.let { available ->
            if (available){
                viewModelScope.launch(Dispatchers.IO){
                    repository.getRecipes(params).collect { result ->
                        when(result){
                            is NetworkResult.Loading ->{
                                //显示网络加载UI
                                showLoadAnimation.postValue(true)
                            }
                            is NetworkResult.Success ->{
                                //请求成功

                                result.data?.let { loadRecipe ->
                                    //判断是追加还是替换
                                    if (isAppend){
                                        //记载更多
                                        //获取原来的请求对象
                                        val oldRecipe = foodRecipe.value
                                        //创建新的FoodRecipe对象
                                        val newRecipe = FoodRecipe(
                                            oldRecipe.results.size + loadRecipe.results.size,
                                            0,
                                            oldRecipe.results + loadRecipe.results,
                                            oldRecipe.totalResults
                                        )
                                        //更新
                                        foodRecipe.postValue(newRecipe)
                                        //更新数据库中的数据
                                        saveRecipeToRoom(newRecipe)
                                    }else{
                                        //搜索
                                        foodRecipe.postValue(result.data)
                                        //更新数据库中的数据
                                        saveRecipeToRoom(result.data)
                                    }
                                }

                                showLoadAnimation.postValue(false)
                            }
                            is NetworkResult.Failure ->{
                                //请求失败
                                showLoadAnimation.postValue(false)
                            }
                        }
                    }
                }
            }
        }
    }
    //构建请求参数
    /*
    apiKey=6e289cb8b5374e2e907d1224ce72cba5
    cuisine=Chinese
    addRecipeInformation=true
    type=main course
    number=1
    addRecipeInstructions=true
    fillIngredients=true
     */
    private fun buildRequestParameters(
        offset: Int = 0,
        query: String? = mQuery,
        mealType: String? = this.mealType,
        dietType: String? = this.dietType
        ):Map<String,String>{
        val params = hashMapOf<String,String>().apply {
            put(OFFSET_KEY,offset.toString())
            query?.let {
                put(QUERY_KEY,query)
            }
            mealType?.let{
                put(TYPE_KEY,mealType)
            }
            dietType?.let {
                put(DIET_KEY,dietType)
            }
            put(CUISINE_KEY,"Chinese")
            put(API_KEY, APIKEY)
            put(ADD_RECIPE_INFORMATION_KEY,"true")
            put(ADD_RECIPE_INSTRUCTIONS_KEY,"true")
            put(FILL_INGREDIENTS_KEY,"true")
            put(NUMBER_KEY,"2")
        }

        return params
    }

    //添加网络状态监听器
    private fun addNetworkListener(){
        //获取网络连接管理器对象
        val cm = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        //创建Request
        val networkRequest = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        //获取当前网络连接状态
        val networkInfo = cm.activeNetworkInfo
        isNetworkAvailable.postValue( networkInfo != null && networkInfo.isConnected)

        //创建回调对象
        networkCallback = object : ConnectivityManager.NetworkCallback(){
            override fun onAvailable(network: Network) {
                //如果之前没有网络连接，此刻才会发送一个更新
                isNetworkAvailable.postValue(true)
            }

            override fun onLost(network: Network) {
                //如果之前没有网络连接，此刻才会发送一个更新
                isNetworkAvailable.postValue(false)
            }

            override fun onUnavailable() {
                isNetworkAvailable.postValue(false)
            }
        }
        cm.registerNetworkCallback(networkRequest,networkCallback)
    }

    //将foodRecipe写入数据库中
    private suspend fun saveRecipeToRoom(foodRecipe: FoodRecipe){
        repository.insertRecipe(RecipesEntity(foodRecipe,1))
    }
    fun getRecipesFromRoom(){
        viewModelScope.launch(Dispatchers.IO){
            repository.getRecipes().collect { result ->
                when(result){
                    is RoomResult.Loading -> {
                        showLoadAnimation.postValue(true)
                    }
                    is RoomResult.Success -> {
                        if (result.entities.isNotEmpty()){
                            foodRecipe.postValue(result.entities[0].foodRecipe)
                        }
                        showLoadAnimation.postValue(false)
                    }
                }
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        val cm = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        cm.unregisterNetworkCallback(networkCallback)
    }
}










